/*
 * Barebones implementation of displaying camera preview.
 * 
 * Created by lisah0 on 2012-02-24
 */
package com.darryring.libview;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PreviewCallback;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.io.IOException;
import java.util.List;

/**
 * 摄像头预览组件
 */
public class LibCameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    public void setCallback(Callback mCallback) {
        this.mCallback = mCallback;
    }

    public interface  Callback{
        void initCamera(Camera _camera);
    }


    String TAG="LibCameraPreview";
    private SurfaceHolder mHolder;
    private Camera mCamera;
    private PreviewCallback previewCallback;
    private AutoFocusCallback autoFocusCallback;
    private Callback mCallback;
    private int mCameraID;
    public LibCameraPreview(Context context,
                            PreviewCallback previewCb,
                            AutoFocusCallback autoFocusCb) {
        super(context);
        previewCallback = previewCb;
        autoFocusCallback = autoFocusCb;
        /*
         * Set camera to continuous focus if supported, otherwise use
         * software auto-focus. Only works for API level >=9.
         */
        /*
        Camera.Parameters parameters = camera.getParameters();
        for (String f : parameters.getSupportedFocusModes()) {
            if (f == Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) {
                mCamera.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                autoFocusCallback = null;
                break;
            }
        }
        */
        mCameraID = getBackCameraID();
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);

        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        Log.i(TAG,"surfaceCreated...");
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            if(mCamera==null){
                getCamera(mCameraID);
            }
            mCamera.setPreviewDisplay(holder);
        } catch (IOException e) {
            Log.d("DBG", "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Camera preview released in activity
        Log.i(TAG,"surfaceDestroyed...");
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Log.i(TAG,"surfaceChanged...");
        /*
         * If your preview can change or rotate, take care of those events here.
         * Make sure to stop the preview before resizing or reformatting it.
         */
        if (mHolder.getSurface() == null){
          // preview surface does not exist
          return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }

        try {
            // Hard code camera surface rotation 90 degs to match Activity view in portrait
            mCamera.setDisplayOrientation(determineDisplayOrientation());

            mCamera.setPreviewDisplay(mHolder);
            mCamera.setPreviewCallback(previewCallback);
            mCamera.startPreview();
            mCamera.autoFocus(autoFocusCallback);
        } catch (Exception e){
            Log.d("DBG", "Error starting camera preview: " + e.getMessage());
        }
    }
    private int determineDisplayOrientation() {
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        Camera.getCameraInfo(mCameraID, cameraInfo);
        // Clockwise rotation needed to align the window display to the natural position
        int rotation = ((Activity) getContext()).getWindowManager().getDefaultDisplay().getRotation();
        int degrees = 0;
        int mCameraRotation;
        switch (rotation) {
            case Surface.ROTATION_0: {
                degrees = 0;
                break;
            }
            case Surface.ROTATION_90: {
                degrees = 90;
                break;
            }
            case Surface.ROTATION_180: {
                degrees = 180;
                break;
            }
            case Surface.ROTATION_270: {
                degrees = 270;
                break;
            }
        }

        int displayOrientation;

        // CameraInfo.Orientation is the angle relative to the natural position of the device
        // in clockwise rotation (angle that is rotated clockwise from the natural position)
        if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            // Orientation is angle of rotation when facing the camera for
            // the camera image to match the natural orientation of the device
            displayOrientation = (cameraInfo.orientation + degrees) % 360;
            displayOrientation = (360 - displayOrientation) % 360;
        } else {
            displayOrientation = (cameraInfo.orientation - degrees + 360) % 360;
        }

        mCameraRotation = displayOrientation;
        return mCameraRotation;
    }

    private int getFrontCameraID() {
        PackageManager pm = getContext().getPackageManager();
        if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
            return Camera.CameraInfo.CAMERA_FACING_FRONT;
        }

        return getBackCameraID();
    }

    private int getBackCameraID() {
        return Camera.CameraInfo.CAMERA_FACING_BACK;
    }
    private void getCamera(int cameraID) {
        try {
            mCamera = Camera.open(cameraID);
            Camera.Parameters  parameters = mCamera.getParameters();
            if(parameters!=null){
                List<Camera.Size> _size = parameters.getSupportedPreviewSizes();
                if (_size != null) {
                    for (Camera.Size _s : _size) {
                        Log.i(TAG, "PreviewSizes--->" + _s.width + "x" + _s.height);
                    }
                }
                List<String> _focus = parameters.getSupportedFocusModes();
                if (_focus != null && _focus.size() > 0) {
                    if(_focus.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)){
                        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                    }
                    else if(_focus.contains(Camera.Parameters.FOCUS_MODE_AUTO)){
                        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                    }
                }
                if (_size.size() >= 2) {

                    Camera.Size _set = null;
                    Camera.Size _s1 = _size.get(0);
                    Camera.Size _s2 = _size.get(_size.size() - 1);
                    if (_s2.width > _s1.width) {
                        //从小到大
                        _set = _s2;
                    } else {
                        //从大到小
                        _set = _s1;
                    }
                    parameters.setPreviewSize(_set.width, _set.height);
                }
                try {
                    mCamera.setParameters(parameters);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }

            if(mCallback!=null){
                mCallback.initCamera(mCamera);
            }
        } catch (Exception e) {
            Log.d(TAG, "Can't open camera with id " + cameraID);
            e.printStackTrace();
        }
    }
    private boolean previewing;
    public void releaseCamera() {
        Log.i(TAG,"releaseCamera...");
        if (mCamera != null) {
            previewing = false;
            mCamera.setPreviewCallback(null);
            mCamera.release();
            mCamera = null;
        }
    }
    public boolean isPreviewing() {
        return previewing;
    }
    public void setPreviewing(boolean previewing) {
        this.previewing = previewing;
    }
    public void startPreview(){
        Log.i(TAG,"startPreview...");
        if(mCamera!=null){
            mCamera.startPreview();
        }
    }
    public void setPreviewCallback(PreviewCallback _call){
        Log.i(TAG,"setPreviewCallback...");
        if(mCamera!=null){
            mCamera.setPreviewCallback(_call);
        }
    }
    private Camera.PictureCallback mPictureCallback;

    /**
     * @param _call
     */
    public void setPictureCallback(Camera.PictureCallback _call){
        mPictureCallback = _call;

    }
    /**
     * 拍照
     */
    public void takePicture(){
        if(mCamera!=null){
            mCamera.takePicture(null,null,mPictureCallback);
        }
    }

    public void cancelAutoFocus(){
        if(mCamera!=null){
            mCamera.cancelAutoFocus();
        }
    }

    /**
     *
     */
    public void stopPreview(){
        Log.i(TAG,"stopPreview...");
        if(mCamera!=null){
            mCamera.stopPreview();
        }
    }
    public void autoFocus(AutoFocusCallback _call){
        Log.i(TAG,"autoFocus...");
        if(mCamera!=null) {
            mCamera.autoFocus(_call);
        }
    }
}
